using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using Core.Runtime;
using UnityEngine;

namespace GameLauncher.Runtime
{
    public class HotFixStateMachine
    {
        public async UniTask Run()
        {
            try
            {
                using (mCts = new CancellationTokenSource())
                {
                    mCurrentState = GetFirstState();

                    try
                    {
                        while (mCurrentState != null && !mCts.IsCancellationRequested)
                        {
                            var result = await mCurrentState.Execute().AttachExternalCancellation(mCts.Token);
                            mCurrentState = DetermineNextState(mCurrentState, result);
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        Debug.Log("状态机已被取消");
                    }
                }
            }
            catch (Exception ex) when (ex is not OperationCanceledException)
            {
                Debug.LogError($"状态机异常终止: {ex.ToString()}");
                ErrorQuitEngine("系统内部错误");
            }
        }

        public void Cancel()
        {
            mCts?.Cancel();
            mCts?.Dispose();
            mCts = null;
        }

        private HotFixState DetermineNextState(HotFixState current, StateResult result)
        {
            return current switch
            {
                PackageOnlyState packageOnlyState => HandlePackageOnlyResult(packageOnlyState, result),
                AssetCheckState assetCheckState => HandleAssetCheckResult(assetCheckState, result),
                AssetUpdateState assetUpdateState => HandleAssetUpdateResult(assetUpdateState, result),
                LoadAssemblyState loadAssemblyState => HandleLoadAssemblyResult(loadAssemblyState, result),
                EditorModeState editorModeState => HandleEditorModeResult(editorModeState, result),
                _ => null
            };
        }

        private HotFixState GetFirstState()
        {
#if UNITY_EDITOR
            if (GameSettings.IsEditorMode)
            {
                return new EditorModeState();
            }
#endif
            HotFixUI.Initialize();
            return GameSettings.RuntimeMode switch
            {
                RuntimeMode.PackageOnly => new PackageOnlyState(),
                RuntimeMode.Updatable => new AssetCheckState(),
                _ => throw new ArgumentException("Invalid runtime mode")
            };
        }

        private HotFixState HandlePackageOnlyResult(PackageOnlyState state, StateResult result)
        {
            if (!result.IsSuccess)
            {
                ErrorQuitEngine(result.Error);
                throw new ArgumentException(result.Error);
            }
            else
            {
                return new LoadAssemblyState();
            }
        }

        private HotFixState HandleAssetCheckResult(AssetCheckState state, StateResult result)
        {
            if (!result.IsSuccess)
            {
                ErrorQuitEngine(result.Error);
                throw new ArgumentException(result.Error);
            }
            else
            {
                return new AssetUpdateState();
            }
        }

        private HotFixState HandleAssetUpdateResult(AssetUpdateState state, StateResult result)
        {
            if (!result.IsSuccess)
            {
                ErrorQuitEngine(result.Error);
                throw new ArgumentException(result.Error);
            }
            else
            {
                return new LoadAssemblyState();
            }
        }


        private HotFixState HandleLoadAssemblyResult(LoadAssemblyState state, StateResult result)
        {
            return null;
        }

        private HotFixState HandleEditorModeResult(EditorModeState state, StateResult result)
        {
            return null;
        }

        private void ErrorQuitEngine(string error)
        {
            HotFixUI.ShowOneMessageBox(error, () =>
            {
                Application.Quit();
#if UNITY_EDITOR
                UnityEditor.EditorApplication.isPlaying = false;
#endif
            });
        }


        private HotFixState mCurrentState;
        private CancellationTokenSource mCts;
    }
}